#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include "../my_codeh/speech.h"
#include "lvgl/lvgl.h"
#include "lvgl/demos/lv_demos.h"
#include <pthread.h>
#include <time.h>
#include "../my_codeh/display.h"
#include <sys/wait.h>
#include "../my_codeh/say_boot.h"
extern lv_obj_t *app_box_scr;
extern lv_obj_t * win1;
extern lv_obj_t * gif;
extern lv_obj_t *label_end ;
extern int jinxflag ;
char *mp3[2] = {"1.mp3","2.mp3"};
char *bmp[4] = {"1.bmp","2.bmp","3.bmp","4.bmp"};
int index_mp3 = 0;		//	保存音频的下标
int index_bmp = 0;		//	保存图片的下标

/*
	过程： 
        在开发板(客户端)上进行录音  -->  音频文件 yysb.pcm 
        通过网络编程(UDP) 将音频文件 发送给虚拟机(服务器) 
        服务器接收文件 并 开始识别该音频文件 
        将识别的结果 发回给 客户端 
        客户端接收到识别的结果之后，根据结果 执行相应的控制操作即可
*/

int client_sock;    				//客户端套接字 
struct sockaddr_in server_addr;    //服务器的ip地址 
socklen_t addrlen; 

//初始化的客户端的套接字 

int init_client_socket()
{
    //创建套接字  UDP 
    client_sock = socket( AF_INET, SOCK_DGRAM, 0 );
    if( client_sock == -1 )
    {
		perror("client socket error ");
		return -1;
    }

    //设置服务器的ip和端口号 
    addrlen = sizeof(server_addr);
	memset(&server_addr,0,sizeof(server_addr));		        //	先把所有的成员变量值设置为 0
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(8899);       					//  指定 PORT 
	server_addr.sin_addr.s_addr = inet_addr("192.168.31.11");  	//  指定 IP

    return 0;
}
void end_client_socket()
{
	close(client_sock);
}

/*
	GetIdtoDo:	根据指令 执行相应的控制操作 
	@id:		识别到的关键字的 ID
	@plcd:		第一个像素点的地址
*/
int GetIdtoDo(int id)
{
    if(id == 1000)    //钢琴块
    {
		printf("play piano\n");
        lv_obj_add_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
        if(jinxflag==0)
        {
            if(fork() == 0) //  子进程,播放媒体文件
            {
                int r = execlp("./piano",NULL);
                if(r == -1)
                {
                    perror("execlp error");
                    exit(-1);
                }
            }
            else            //  父进程,执行控制命令
            {
                wait(NULL);
                lv_obj_remove_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
                
            }
        }
        else if(jinxflag==88)
        {
            jinxflag=3;
        }
    }
    else if( id == 1001 )   //扫雷 
    {
        printf("play bomb\n");
        lv_obj_add_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
        if(jinxflag==0)
        {
            if(fork() == 0) //  子进程,播放媒体文件
            {
                int r = execlp("./cell",NULL);
                if(r == -1)
                {
                    perror("execlp error");
                    exit(-1);
                }
            }
            else            //  父进程,执行控制命令
            {
                wait(NULL);
                lv_obj_remove_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
            }
        }
        else if(jinxflag==88)
        {
            jinxflag=4;
        }
    }
    else if( id == 1002) //视频播放器
    {
        printf("open video\n");
        lv_obj_add_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
        if(jinxflag==0)
        {
            if(fork() == 0) //  子进程,播放媒体文件
            {
                int r = execlp("./video",NULL);
                if(r == -1)
                {
                    perror("execlp error");
                    exit(-1);
                }
            }
            else            //  父进程,执行控制命令
            {
                wait(NULL);
                lv_obj_remove_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
            }
        }
        else if(jinxflag==88)
        {
            jinxflag=5;
        }
    }
    else if( id == 1003)
    {
        printf("play wuzi\n");
        lv_obj_add_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
        if(jinxflag==0)
        {
            if(fork() == 0) //  子进程,播放媒体文件
            {
                int r = execlp("./wuzi",NULL);
                if(r == -1)
                {
                    perror("execlp error");
                    exit(-1);
                }
            }
            else            //  父进程,执行控制命令
            {
                wait(NULL);
                lv_obj_remove_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
            }
        }
        else if(jinxflag==88)
        {
            jinxflag=6;
        }
    }
    else if( id == 1004)
    {   

        printf("exit game box\n");
        lv_obj_add_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
        
        win1=lv_obj_create(lv_screen_active());
        lv_obj_set_size(win1,480,480);
        lv_obj_set_pos(win1,160,0);
        gif=lv_gif_create(win1);
        lv_gif_set_src(gif,"A:/lingke/preview.gif");
        lv_obj_set_align(gif,LV_ALIGN_CENTER);//动图显示

        label_end = lv_label_create(win1);//文字显示
        lv_label_set_text(label_end, "Good Game");
        lv_obj_set_style_text_font(label_end, &lv_font_montserrat_32, 0);
        lv_obj_set_style_text_color(label_end, lv_color_hex(0xEE6AA7), 0);  // 粉色文字
        lv_obj_center(label_end);
        


    }
    else if( id == 1012)
    {
        printf("say_boot\n");
        jinxflag=88;
        lv_obj_add_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
        if(fork() == 0) //  子进程,播放媒体文件
        {
            create_say_boot_screen();
        }
        else            //  父进程,执行控制命令
        {
            wait(NULL);
            lv_obj_remove_flag(app_box_scr, LV_OBJ_FLAG_HIDDEN);
        }
    }
    else if( id == 1013)
    {
        jinxflag=1;
    }
    else if (id == 1014)
    {
        jinxflag=2;
    }
    else if (id == 1005)
    {
        jinxflag=7;
    }
    else if (id == 1015)
    {
        jinxflag=8;
    }
    else if (id == 1016)
    {
        jinxflag=9;
    }
    else if (id == 1017)
    {
        jinxflag=10;
    }
    else if (id == 1018)
    {
        jinxflag=13;
    }
    else if (id == 1006)
    {
        jinxflag=11;
    }
    else if (id == 1007)
    {
        jinxflag=12;
    }

    else
    {
        printf("重新输入语音\n");
    }

    //... 	其他情况的操作,根据 yysb.bnf 中的 ID 来写
}

/*
	Automatic_Speech_Recognition:	语音识别的客户端 
	@plcd:		第一个像素点的地址
	过程： 
        在开发板(客户端)上进行录音  -->  音频文件 yysb.pcm 
        通过网络编程(UDP) 将音频文件 发送给虚拟机(服务器) 
        服务器接收文件 并 开始识别该音频文件 
        将识别的结果 发回给 客户端 
        客户端接收到识别的结果之后，根据结果 执行相应的控制操作即可
*/
int Automatic_Speech_Recognition()
{
    //	1、录音4s 
    printf("开始录音,请说话!\n");
    system("arecord -d4 -c1 -r16000 -traw -fS16_LE  ./yysb.pcm");

    //	2、通过网络编程，发送音频文件 
    //	2.1 打开文件 
    int fd = open( "./yysb.pcm", O_RDWR);
    if( fd == -1 )
    {
		perror("open yysb.pcm error ");
		return -1;
    }

    int re ;
    char buf[1024]={0};			//	保存通信数据

    //	2.2 首先给服务器 发送起始信号 "start!!!"
    sendto(client_sock,"start!!!",9,0,(struct sockaddr *)&server_addr, addrlen);
    //	2.3	等待服务器的回应 "ok!!!" 
    char ack[32] = {0};
    re = recvfrom(client_sock, ack, 32, 0, NULL, NULL );
    if(strcmp(ack,"ok!!!") != 0) 
    {
		perror("recv ok!!! error ");
		return -1;
    }

	//	2.4 开始传输文件
    printf("正在识别你的操作....\n");
    printf("开始传输文件\n");
    while(1)
    {
        //	先读取文件内容 
        re = read(fd,buf,1024);		//	读取本地的录音文件内容,发送给服务器
        if(re == -1) 				//	出错 
        {
			perror("read hehe.pcm error ");
			break;
        }
        else if(re == 0)  	//	读完了 
        {
            //	读完之后，发送结束信号 "quit!!!"
            sendto(client_sock,"quit!!!",8,0,(struct sockaddr *)&server_addr, addrlen);
            break;
        }
        else if(re > 0)   	//	读取成功 
        {
            //	发送数据
            re = sendto(client_sock,buf,re,0 ,(struct sockaddr *)&server_addr, addrlen);
            if(re == -1)
            {
				perror("sendto file error ");
				break;
            }

            //	等待服务器的回应我，再去发送写一个数据 "next!!!"
            recvfrom(client_sock,ack,32,0,NULL,NULL);
            if(strcmp(ack, "next!!!") != 0)
            {
                //	没有收到回复，说明中间出问题了 ，那么就退出
                printf("no next!!!\n");

                //	先发送结束信号 "quit!!!"
                sendto( client_sock, "quit!!!", 8, 0, (struct sockaddr *)&server_addr, addrlen );
                break; 
            }
        }
    }

    //	3、接收识别的结果 
    printf("等待识别...\n");

    //	4、接收结果
    re = recvfrom(client_sock,buf,1024,0,NULL,NULL);   
    printf("识别完成 ... re = %d \n buf = %s\n",re,buf);
    

    //	5、从结果中 提取指令 id (yysb.bnf 这个文件里面的指令)
    int id = 0;

    if(strcmp(buf,"没有识别结果!!!") != 0  )  	//	识别成功 
    {
        //	buf[]   "id=1001"
        int i = 0;
        while(buf[i])
        {
            if(strncmp(buf+i,"id=",3) == 0 )
            {
                //	找到了id所在的位置 
                i = i+4;
                id = (buf[i]-'0')*1000 + (buf[i+1]-'0')*100 + (buf[i+2]-'0')*10 + (buf[i+3]-'0') ; 
                printf("id = %d\n", id );

                //5.根据指令 执行相应的控制操作 
				GetIdtoDo(id);
				break;
            }
			i++;
        }
    } 
    else								//	识别失败 
    {
		printf("我没听清楚 !!!\n");
    }

    //关闭文件 
    close(fd);
}
